using Microsoft.Extensions.Logging;
using SeataNet.Core.Configuration;
using SeataNet.Core.Exceptions;
using SeataNet.Core.Protocol;
using System.Collections.Concurrent;
using System.Text.Json;

namespace SeataNet.Core.RPC
{
    /// <summary>
    /// RPC客户端工厂
    /// </summary>
    public interface IRpcClientFactory
    {
        IRpcClient CreateClient(string name);
        IRpcClient GetClient(string name);
        void RemoveClient(string name);
        void Dispose();
    }

    /// <summary>
    /// 默认RPC客户端工厂
    /// </summary>
    public class DefaultRpcClientFactory : IRpcClientFactory, IDisposable
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly SeataConfiguration _configuration;
        private readonly ILogger<DefaultRpcClientFactory> _logger;
        private readonly ILoggerFactory _loggerFactory;
        private readonly ConcurrentDictionary<string, IRpcClient> _clients;
        private volatile bool _disposed = false;

        public DefaultRpcClientFactory(
            IHttpClientFactory httpClientFactory,
            SeataConfiguration configuration,
            ILogger<DefaultRpcClientFactory> logger,
            ILoggerFactory loggerFactory)
        {
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
            _logger = logger;
            _loggerFactory = loggerFactory;
            _clients = new ConcurrentDictionary<string, IRpcClient>();
        }

        public IRpcClient CreateClient(string name)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultRpcClientFactory));
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (_clients.ContainsKey(name))
            {
                throw new InvalidOperationException($"RPC客户端已存在: {name}");
            }

            var httpClient = _httpClientFactory.CreateClient($"seata-{name}");

            // 配置HttpClient
            httpClient.Timeout = _configuration.Transport.Timeout;
            
            var loadBalancer = CreateLoadBalancer();
            var retryPolicy = CreateRetryPolicy();
            var circuitBreaker = CreateCircuitBreaker();
            var serializer = CreateSerializer();
            
            var channelManager = new DefaultChannelManager(
                httpClient,
                _configuration,
                _loggerFactory.CreateLogger<DefaultChannelManager>(),
                _loggerFactory,
                loadBalancer,
                retryPolicy,
                circuitBreaker,
                serializer);

            var connectionManager = new DefaultConnectionManager(
                httpClient,
                _configuration,
                _loggerFactory.CreateLogger<DefaultConnectionManager>(),
                _loggerFactory);

            var client = new DefaultRpcClient(
                _loggerFactory.CreateLogger<DefaultRpcClient>(),
                httpClient);
            
            _clients[name] = client;
            _logger.LogDebug($"创建RPC客户端: {name}");
            
            return client;
        }

        public IRpcClient GetClient(string name)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultRpcClientFactory));
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (_clients.TryGetValue(name, out var client))
            {
                return client;
            }
            
            return null;
        }

        public void RemoveClient(string name)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultRpcClientFactory));
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (_clients.TryRemove(name, out var client))
            {
                if (client is IDisposable disposableClient)
                {
                    disposableClient.Dispose();
                }
                
                _logger.LogDebug($"移除RPC客户端: {name}");
            }
        }

        private ILoadBalancer CreateLoadBalancer()
        {
            var loadBalancerType = _configuration.Transport.LoadBalancerType?.ToLowerInvariant();
            
            return loadBalancerType switch
            {
                "random" => new RandomLoadBalancer(),
                "roundrobin" => new RoundRobinLoadBalancer(),
                _ => new RoundRobinLoadBalancer()
            };
        }

        private IRetryPolicy CreateRetryPolicy()
        {
            var maxAttempts = _configuration.Transport.MaxRetryAttempts > 0 ? _configuration.Transport.MaxRetryAttempts : 3;
            var initialDelay = TimeSpan.FromMilliseconds(_configuration.Transport.RetryInterval > 0 ? _configuration.Transport.RetryInterval : 1000);
            
            var retryPolicyType = _configuration.Transport.RetryPolicyType?.ToLowerInvariant();
            
            return retryPolicyType switch
            {
                "exponential" => new ExponentialBackoffRetryPolicy(
                    maxAttempts,
                    initialDelay,
                    TimeSpan.FromMilliseconds(30000)),
                "fixed" => new FixedIntervalRetryPolicy(maxAttempts, initialDelay),
                _ => new FixedIntervalRetryPolicy(maxAttempts, initialDelay)
            };
        }

        private ICircuitBreaker CreateCircuitBreaker()
        {
            var failureThreshold = _configuration.Transport.CircuitBreakerFailureThreshold > 0 
                ? _configuration.Transport.CircuitBreakerFailureThreshold 
                : 5;
            
            var recoveryTimeout = TimeSpan.FromMilliseconds(
                _configuration.Transport.CircuitBreakerRecoveryTimeout > 0 
                    ? _configuration.Transport.CircuitBreakerRecoveryTimeout 
                    : 30000);
            
            return new DefaultCircuitBreaker(failureThreshold, recoveryTimeout);
        }

        private IMessageSerializer CreateSerializer()
        {
            var serializerType = _configuration.Transport.SerializerType?.ToLowerInvariant();

            return serializerType switch
            {
                "json" => new JsonMessageSerializer(_loggerFactory.CreateLogger<JsonMessageSerializer>()),
                "binary" => new BinaryMessageSerializer(_loggerFactory.CreateLogger<BinaryMessageSerializer>()),
                _ => new JsonMessageSerializer(_loggerFactory.CreateLogger<JsonMessageSerializer>())
            };
        }

        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;
            
            foreach (var client in _clients.Values)
            {
                if (client is IDisposable disposableClient)
                {
                    disposableClient.Dispose();
                }
            }
            
            _clients.Clear();
        }
    }

    /// <summary>
    /// RPC客户端池
    /// </summary>
    public interface IRpcClientPool
    {
        Task<IRpcClient> GetClientAsync(string name, CancellationToken cancellationToken = default);
        Task ReturnClientAsync(string name, IRpcClient client);
        void Clear();
    }

    /// <summary>
    /// 默认RPC客户端池
    /// </summary>
    public class DefaultRpcClientPool : IRpcClientPool, IDisposable
    {
        private readonly IRpcClientFactory _clientFactory;
        private readonly ILogger<DefaultRpcClientPool> _logger;
        private readonly ConcurrentDictionary<string, ConcurrentQueue<IRpcClient>> _pools;
        private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores;
        private readonly int _maxPoolSize;
        private volatile bool _disposed = false;

        public DefaultRpcClientPool(
            IRpcClientFactory clientFactory,
            ILogger<DefaultRpcClientPool> logger,
            int maxPoolSize = 10)
        {
            _clientFactory = clientFactory;
            _logger = logger;
            _pools = new ConcurrentDictionary<string, ConcurrentQueue<IRpcClient>>();
            _semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();
            _maxPoolSize = maxPoolSize;
        }

        public async Task<IRpcClient> GetClientAsync(string name, CancellationToken cancellationToken = default)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultRpcClientPool));
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            var pool = _pools.GetOrAdd(name, _ => new ConcurrentQueue<IRpcClient>());
            var semaphore = _semaphores.GetOrAdd(name, _ => new SemaphoreSlim(_maxPoolSize, _maxPoolSize));
            
            await semaphore.WaitAsync(cancellationToken);
            
            try
            {
                if (pool.TryDequeue(out var client))
                {
                    _logger.LogDebug($"从池中获取RPC客户端: {name}");
                    return client;
                }
                
                _logger.LogDebug($"创建新的RPC客户端: {name}");
                return _clientFactory.CreateClient(name);
            }
            catch
            {
                semaphore.Release();
                throw;
            }
        }

        public async Task ReturnClientAsync(string name, IRpcClient client)
        {
            if (_disposed)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

            if (!_pools.TryGetValue(name, out var pool) || 
                !_semaphores.TryGetValue(name, out var semaphore))
            {
                _logger.LogWarning($"未找到RPC客户端池: {name}");
                return;
            }

            try
            {
                // 检查客户端是否仍然有效
                if (client.IsConnected)
                {
                    if (pool.Count < _maxPoolSize)
                    {
                        pool.Enqueue(client);
                        _logger.LogDebug($"将RPC客户端返回到池中: {name}");
                    }
                    else
                    {
                        _logger.LogDebug($"RPC客户端池已满，丢弃客户端: {name}");
                        if (client is IDisposable disposableClient)
                        {
                            disposableClient.Dispose();
                        }
                    }
                }
                else
                {
                    _logger.LogDebug($"RPC客户端已断开连接，丢弃客户端: {name}");
                    if (client is IDisposable disposableClient)
                    {
                        disposableClient.Dispose();
                    }
                }
            }
            finally
            {
                semaphore.Release();
            }
        }

        public void Clear()
        {
            foreach (var pool in _pools.Values)
            {
                while (pool.TryDequeue(out var client))
                {
                    if (client is IDisposable disposableClient)
                    {
                        disposableClient.Dispose();
                    }
                }
            }
            
            _pools.Clear();
            
            foreach (var semaphore in _semaphores.Values)
            {
                semaphore.Dispose();
            }
            
            _semaphores.Clear();
        }

        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;
            Clear();
        }
    }
}